package cn.iocoder.mall.order.biz.service;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.common.framework.constant.CommonConstant;
import cn.iocoder.common.framework.constant.DeletedStatusEnum;
import cn.iocoder.common.framework.util.DateUtil;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.common.utils.common.util.DateUtils;
import cn.iocoder.common.utils.common.util.ObjectUtils;
import cn.iocoder.common.utils.common.util.TimeUtils;
import cn.iocoder.common.utils.common.util.encryption.AesEncryptUtil;
import cn.iocoder.common.utils.common.util.encryption.EncryptedString;
import cn.iocoder.common.utils.common.util.json.JacksonUtils;
import cn.iocoder.mall.order.api.OrderService;
import cn.iocoder.mall.order.api.bo.*;
import cn.iocoder.mall.order.api.constant.OrderErrorCodeEnum;
import cn.iocoder.mall.order.api.constant.OrderHasReturnExchangeEnum;
import cn.iocoder.mall.order.api.constant.OrderStatusEnum;
import cn.iocoder.mall.order.api.constant.PayAppId;
import cn.iocoder.mall.order.api.dto.*;
import cn.iocoder.mall.order.api.vo.OrdersVO;
import cn.iocoder.mall.order.biz.constants.OrderDeliveryTypeEnum;
import cn.iocoder.mall.order.biz.convert.*;
import cn.iocoder.mall.order.biz.dao.*;
import cn.iocoder.mall.order.biz.dataobject.*;
import cn.iocoder.mall.order.biz.utils.GeneratorSnowFlakeIDUtils;
import cn.iocoder.mall.pay.api.PayTransactionService;
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO;
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionCreateDTO;
import cn.iocoder.mall.product.api.ProductSpuService;
import cn.iocoder.mall.product.api.bo.ProductSkuDetailBO;
import cn.iocoder.mall.product.api.dto.ProductSkuDecreaseNumDTO;
import cn.iocoder.mall.promotion.api.CouponService;
import cn.iocoder.mall.shop.api.ShopClerkRelationShipService;
import cn.iocoder.mall.shop.api.ShopService;
import cn.iocoder.mall.user.api.UserAddressService;
import com.google.common.collect.Lists;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 订单 service impl
 *
 * @author Sin
 * @time 2019-03-16 15:08
 */
@Slf4j
@Service
@org.apache.dubbo.config.annotation.Service(validation = "true", version = "${dubbo.provider.OrderService.version}")
public class OrderServiceImpl implements OrderService {

    /**
     * 支付过期时间 120 分钟
     */
    public static final int PAY_EXPIRE_TIME = 120;
    /***
     * 订单超时时间  120分钟
     * **/

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderItemMapper orderItemMapper;
    @Autowired
    private OrderLogisticsMapper orderLogisticsMapper;
    @Autowired
    private OrderLogisticsDetailMapper orderLogisticsDetailMapper;
    @Autowired
    private OrderRecipientMapper orderRecipientMapper;
    @Autowired
    private OrderCancelMapper orderCancelMapper;
    @Autowired
    private OrderReturnMapper orderReturnMapper;
    @Autowired
    private GeneratorSnowFlakeIDUtils generatorSnowFlakeIDUtils;
    @Autowired
    private CartServiceImpl cartService;

    @Resource
    private RocketMQTemplate rocketMQTemplate;

    @Resource
    private OrderCredentialMapper orderCredentialMapper;
    @Reference(validation = "true", version = "1.0.0")
    private ProductSpuService productSpuService;
    @Reference(validation = "true", version = "1.0.0")
    private UserAddressService userAddressService;
    @Reference(validation = "true", version = "1.0.0")
    private PayTransactionService payTransactionService;
    @Reference(validation = "true", version = "1.0.0")
    private CouponService couponService;
    @Reference(validation = "true", version = "1.0.0")
    private ShopClerkRelationShipService relationShipService;
    @Reference(validation = "true", version = "1.0.0")
    private ShopService shopService;
    @Override
    public CommonResult<OrderPageBO> getOrderPage(OrderQueryDTO orderQueryDTO) {

        int totalCount = orderMapper.selectPageCount(orderQueryDTO);
        if (totalCount == 0) { // TODO FROM 芋艿 TO 小范 Collections.EMPTY_LIST 改成 Collections.emptyList()
            return CommonResult.success(new OrderPageBO().setOrders(Collections.emptyList()).setTotal(0));
        }

        // 获取订单数据
        List<OrderDO> orderDOList = orderMapper.selectPage(orderQueryDTO);

        if (CollectionUtils.isEmpty(orderDOList)) {
            return CommonResult.success(new OrderPageBO().setOrders(Collections.emptyList()).setTotal(totalCount));
        }

        // 获取订单 id
        Set<Long> orderIds = orderDOList.stream()
                .map(orderDO -> orderDO.getId())
                .collect(Collectors.toSet());

        // 获取配送信息
        List<OrderRecipientDO> orderRecipientDOList = orderRecipientMapper.selectByOrderIds(orderIds);
        List<OrderRecipientBO> orderRecipientBOList = OrderRecipientConvert.INSTANCE.convert(orderRecipientDOList);
        Map<Long, OrderRecipientBO> orderRecipientBOMap
                = orderRecipientBOList.stream().collect(Collectors.toMap(OrderRecipientBO::getOrderId, obj -> obj));

        // 获取 订单的 items
        List<OrderItemDO> orderItemDOList = orderItemMapper
                .selectByDeletedAndOrderIds(orderIds, DeletedStatusEnum.DELETED_NO.getValue());
        List<OrderItemBO> orderItemBOList = OrderItemConvert.INSTANCE.convertOrderItemDO(orderItemDOList);

        Map<Long, List<OrderItemBO>> orderItemBOMultimap = orderItemBOList.stream().collect(
                Collectors.toMap(
                        OrderItemBO::getOrderId,
                        item -> Lists.newArrayList(item),
                        (oldVal, newVal) -> {
                            oldVal.addAll(newVal);
                            return oldVal;
                        }
                )
        );

        // 转换 orderDO 为 OrderBO，并设置 item
        List<OrderBO> orderPageBOList = OrderConvert.INSTANCE.convertPageBO(orderDOList);
        List<OrderBO> result = orderPageBOList.stream().map(orderBO -> {
            if (orderItemBOMultimap.containsKey(orderBO.getId())) {
                orderBO.setOrderItems(orderItemBOMultimap.get(orderBO.getId()));
            }
            if (orderRecipientBOMap.containsKey(orderBO.getId())) {
                orderBO.setOrderRecipient(orderRecipientBOMap.get(orderBO.getId()));
            }
            return orderBO;
        }).collect(Collectors.toList());
        return CommonResult.success(
                new OrderPageBO()
                        .setTotal(totalCount)
                        .setOrders(result)
        );
    }

    @Override
    public CommonResult<List<OrderItemBO>> getOrderItems(Long orderId) {
        if (orderMapper.selectById(orderId) == null) {
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_NOT_EXISTENT.getCode());
        }

        List<OrderItemDO> orderItemDOList = orderItemMapper
                .selectByDeletedAndOrderId(DeletedStatusEnum.DELETED_NO.getValue(), orderId);

        List<OrderItemBO> orderItemBOList = OrderItemConvert.INSTANCE.convertOrderItemBO(orderItemDOList);
        return CommonResult.success(orderItemBOList);
    }

    @Override
    public CommonResult<OrderRecipientBO> getOrderRecipientBO(Long orderId) {
        if (orderMapper.selectById(orderId) == null) {
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_NOT_EXISTENT.getCode());
        }

        OrderRecipientDO orderRecipientDO = orderRecipientMapper.selectByOrderId(orderId);
        OrderRecipientBO orderRecipientBO = OrderRecipientConvert.INSTANCE.convert(orderRecipientDO);
        return CommonResult.success(orderRecipientBO);
    }

    @Override
    public CommonResult<OrderInfoBO> info(String userId, Long orderId) {
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (orderDO == null) {
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_NOT_EXISTENT.getCode());
        }

        List<OrderItemDO> itemDOList = orderItemMapper
                .selectByDeletedAndOrderId(DeletedStatusEnum.DELETED_NO.getValue(), orderId);

        List<OrderInfoBO.OrderItem> orderItems
                = OrderItemConvert.INSTANCE.convertOrderInfoWithOrderItem(itemDOList);

        Set<Integer> orderLogisticsIds = itemDOList.stream()
                .filter(o -> o.getOrderLogisticsId() != null)
                .map(o -> o.getOrderLogisticsId())
                .collect(Collectors.toSet());


        // 收件人信息
        OrderRecipientDO orderRecipientDO = orderRecipientMapper.selectByOrderId(orderId);

        // 订单物流信息
        OrderLogisticsDetailDO orderLogisticsDetailDO = null;
        if (!CollectionUtils.isEmpty(orderLogisticsIds)) {
            orderLogisticsDetailDO = orderLogisticsDetailMapper.selectLast(orderLogisticsIds);
        }

        // 检查是否申请退货
        OrderReturnDO orderReturnDO = orderReturnMapper.selectByOrderId(orderId);

        // convert 信息
        OrderInfoBO.LogisticsDetail logisticsDetail
                = OrderLogisticsDetailConvert.INSTANCE.convertLogisticsDetail(orderLogisticsDetailDO);

        OrderInfoBO.Recipient recipient = OrderRecipientConvert.INSTANCE.convertOrderInfoRecipient(orderRecipientDO);
        OrderInfoBO orderInfoBO = OrderConvert.INSTANCE.convert(orderDO);
        orderInfoBO.setRecipient(recipient);
        orderInfoBO.setOrderItems(orderItems);
        orderInfoBO.setLatestLogisticsDetail(logisticsDetail);

        // 是否退货
        if (orderReturnDO != null) {
            orderInfoBO.setHasOrderReturn(orderReturnDO.getStatus());
        } else {
            orderInfoBO.setHasOrderReturn(-1);
        }
        return CommonResult.success(orderInfoBO);
    }

    @Override
    @GlobalTransactional
    public CommonResult<OrderCreateBO> createOrder(OrderCreateDTO orderCreateDTO) {
        String  xid= RootContext.unbind();
        String userId = orderCreateDTO.getUserId();
        List<OrderCreateDTO.OrderItem> orderItemDTOList = orderCreateDTO.getOrderItems();
        List<OrderItemDO> orderItemDOList = OrderItemConvert.INSTANCE.convert(orderItemDTOList);

        // 获取商品信息
        Set<Long> skuIds = orderItemDOList.stream().map(OrderItemDO::getSkuId).collect(Collectors.toSet());
        List<ProductSkuDetailBO> productList = productSpuService.getProductSkuDetailList(skuIds);

        if (orderItemDTOList.size() != productList.size()) { // 校验获得的数量，是否匹配
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_GET_GOODS_INFO_INCORRECT.getCode());
        }
        log.info(JacksonUtils.toJSONString(productList));
        if (orderCreateDTO.getShopId() == null) {

            orderCreateDTO.setShopId(productList.get(0).getSpu().getShopId());
            log.info("shopId is null and set" +productList.get(0).getSpu().getShopId());
        }
        // 价格计算
        CalcOrderPriceBO calcOrderPrice = calcOrderPrice(productList, orderCreateDTO);

        // 设置 orderItem
        Map<Long, ProductSkuDetailBO> productSpuBOMap = productList
                .stream().collect(Collectors.toMap(ProductSkuDetailBO::getId, o -> o)); // 商品 SKU 信息的集合


        Map<Long, CalcOrderPriceBO.Item> priceItemMap = new HashMap<>(); // 商品 SKU 价格的映射
        calcOrderPrice.getItemGroups().forEach(itemGroup ->
                itemGroup.getItems().forEach(item -> priceItemMap.put(item.getId(), item)));
        // 遍历 orderItemDOList 数组，将商品信息、商品价格，设置到其中
        for (OrderItemDO orderItemDO : orderItemDOList) {
            log.info(JacksonUtils.toJSONString(orderItemDO));
            ProductSkuDetailBO productSkuDetailBO = productSpuBOMap.get(orderItemDO.getSkuId());
            if (productSkuDetailBO.getQuantity() <= 0) {
                return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_INSUFFICIENT_INVENTORY.getCode());
            }
            if (productSkuDetailBO.getPrice() <= 0) {
                return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_GOODS_AMOUNT_INCORRECT.getCode());
            }
            // 设置 SKU 信息
            if(productSkuDetailBO.getSpu()!=null&&productSkuDetailBO.getPicURL()!=null){
                orderItemDO.setSkuImage(productSkuDetailBO.getPicURL());

            }
            orderItemDO.setSkuName(productSkuDetailBO.getTitle());
            // 设置价格信息
            CalcOrderPriceBO.Item priceItem = priceItemMap.get(orderItemDO.getSkuId());
            Assert.notNull(priceItem, "商品计算价格为空");
            orderItemDO.setOriginPrice(priceItem.getOriginPrice())
                    .setBuyPrice(priceItem.getBuyPrice())
                    .setPresentPrice(priceItem.getPresentPrice())
                    .setBuyTotal(priceItem.getBuyTotal())
                    .setDiscountTotal(priceItem.getDiscountTotal())
                    .setPresentTotal(priceItem.getPresentTotal());
        }
        RootContext.bind(xid);
        OrderDO orderDO = saveOrderInfo(orderCreateDTO, userId, orderItemDOList, calcOrderPrice);

        // TODO: 2019-03-17 Sin 需要发送 创建成果 MQ 消息，业务扩展和统计
        byte[] bytes= JacksonUtils.toJSONString(new ExpireOrderDTO().setOrderId(orderDO.getId())).getBytes();

        Message message=new Message(CommonConstant.ORDER_EXPIRE,"ORDER",bytes);
        message.setDelayTimeLevel(16);
        try {
            rocketMQTemplate.getProducer().send(message);
        } catch (MQClientException e) {
            e.printStackTrace();
        } catch (RemotingException e) {
            e.printStackTrace();
        } catch (MQBrokerException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        //演示阶段先直接把订单状态设置为 支付完成
        return CommonResult.success(
                new OrderCreateBO()
                        .setId(orderDO.getId())
                        .setOrderNo(orderDO.getOrderNo())
                        .setPayAmount(orderDO.getPayAmount())
        );
    }
    private OrderDO saveOrderInfo(OrderCreateDTO orderCreateDTO, String userId, List<OrderItemDO> orderItemDOList, CalcOrderPriceBO calcOrderPrice) {
        if (orderCreateDTO.getCouponCardId() != null) {
            couponService.useCouponCard(userId, orderCreateDTO.getCouponCardId());
        }


        productSpuService.decreaseProductSkuQuantity(orderItemDOList.stream().map(e ->
                new ProductSkuDecreaseNumDTO(e.getSkuId(), e.getQuantity())).collect(Collectors.toSet()));


        String orderNo = UUID.randomUUID().toString().replace("-", "").substring(0, 16);

        OrderDO orderDO = new OrderDO()
                .setId(generatorSnowFlakeIDUtils.nextId())
                .setUserId(userId)
                .setOrderNo(orderNo)
                .setShopId(orderCreateDTO.getShopId())
                .setBuyPrice(calcOrderPrice.getFee().getBuyTotal())
                .setDiscountPrice(calcOrderPrice.getFee().getDiscountTotal())
                .setLogisticsPrice(calcOrderPrice.getFee().getPostageTotal())
                .setPresentPrice(calcOrderPrice.getFee().getPresentTotal())
                .setPayAmount(calcOrderPrice.getFee().getPresentTotal())
                .setClosingTime(null)
                .setDeliveryTime(null)
                .setPaymentTime(null)
                .setCreateTime(new Date())
                .setStatus(OrderStatusEnum.WAITING_PAYMENT.getValue())
                .setHasReturnExchange(OrderHasReturnExchangeEnum.NO.getValue())
                .setRemark(Optional.ofNullable(orderCreateDTO.getRemark()).orElse(""));
        orderDO.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());


        orderMapper.save(orderDO);


        // order item
        orderItemDOList.forEach(orderItemDO -> {
            orderItemDO
                    .setOrderId(orderDO.getId())
                    .setOrderNo(orderDO.getOrderNo())
                    .setPaymentTime(null)
                    .setDeliveryTime(null)
                    .setReceiverTime(null)
                    .setClosingTime(null)
                    .setHasReturnExchange(OrderStatusEnum.WAITING_PAYMENT.getValue())
                    .setDeliveryType(OrderDeliveryTypeEnum.NONE.getValue())
                    .setStatus(OrderStatusEnum.WAITING_PAYMENT.getValue())
                    .setDeleted(DeletedStatusEnum.DELETED_NO.getValue())
                    .setCreateTime(new Date())
                    .setUpdateTime(null);
        });
        // 一次性插入
        orderItemMapper.insert(orderItemDOList);


        // 创建预订单
        createPayTransaction(orderDO, orderItemDOList, orderCreateDTO.getIp());
        return orderDO;
    }

    private CalcOrderPriceBO calcOrderPrice(List<ProductSkuDetailBO> skus, OrderCreateDTO orderCreateDTO) {
        // 创建计算的 DTO
        CalcOrderPriceDTO calcOrderPriceDTO = new CalcOrderPriceDTO()
                .setUserId(orderCreateDTO.getUserId())
                .setItems(new ArrayList<>(skus.size()))
                .setCouponCardId(orderCreateDTO.getCouponCardId());
        for (OrderCreateDTO.OrderItem item : orderCreateDTO.getOrderItems()) {
            calcOrderPriceDTO.getItems().add(new CalcOrderPriceDTO.Item(item.getSkuId(), item.getQuantity(), true));
        }
        // 执行计算
        return cartService.calcOrderPrice(calcOrderPriceDTO);
    }

    private PayTransactionBO createPayTransaction(OrderDO order, List<OrderItemDO> orderItems, String ip) {
        // TODO sin 支付订单 orderSubject 暂时取第一个子订单商品信息
        String orderSubject = orderItems.get(0).getSkuName();
        Date expireTime = DateUtil.addDate(Calendar.MINUTE, PAY_EXPIRE_TIME);
        return payTransactionService.createTransaction(
                new PayTransactionCreateDTO()
                        .setCreateIp(ip)
                        .setAppId(PayAppId.APP_ID_SHOP_ORDER)
                        .setOrderId(order.getId().toString())
                        .setExpireTime(expireTime)
                        .setPrice(order.getPresentPrice())
                        .setOrderSubject(orderSubject)
                        .setOrderMemo("测试备注") // TODO 芋艿，后面补充
                        .setOrderDescription("测试描述") // TODO 芋艿，后面补充
        );
    }

    @Override // TODO 芋艿，需要确认下这个方法的用途。因为涉及修改价格和数量。
    public CommonResult updateOrderItem(OrderItemUpdateDTO orderUpdateDTO) {
        OrderItemDO orderItemDO = OrderItemConvert.INSTANCE.convert(orderUpdateDTO);
        orderItemMapper.updateById(orderItemDO);

        // TODO: 2019-03-24 sin 需要重新计算金额
        // TODO: 2019-03-24 sin 需要记录日志
        return CommonResult.success(null);
    }

    @Override
    @Transactional
    public CommonResult updateOrderItemPayAmount(Long orderId, Integer orderItemId, Integer payAmount) {
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (orderDO == null) {
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_NOT_EXISTENT.getCode());
        }
        if (payAmount < 0) {
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_PAY_AMOUNT_NOT_NEGATIVE.getCode());
        }

        // 先更新金额
        orderItemMapper.updateById(new OrderItemDO().setId(orderItemId)
//                .setPayAmount(payAmount) TODO 芋艿，这里要修改
        );

        // 再重新计算订单金额
        List<OrderItemDO> orderItemDOList = orderItemMapper
                .selectByDeletedAndOrderId(DeletedStatusEnum.DELETED_NO.getValue(), orderId);
//        Integer price = orderCommon.calculatedPrice(orderItemDOList);
//        Integer amount = orderCommon.calculatedAmount(orderItemDOList);
        Integer price = -1; // TODO 芋艿，这里要修改，价格
        Integer amount = -1;
        orderMapper.updateById(
                new OrderDO()
                        .setId(orderId)
//                        .setPrice(price) TODO 芋艿，这里要修改
                        .setPayAmount(amount)
        );
        return CommonResult.success(null);
    }

    @Override
    @Transactional // TODO 芋艿，要校验下 userId 。不然可以取消任何用户的订单列。
    public CommonResult cancelOrder(Long orderId, Integer reason, String otherReason) {
        // 关闭订单，在用户还未付款的时候可操作
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (orderDO == null) {
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_NOT_EXISTENT.getCode());
        }

        // 检查专题，只有待付款状态才能操作
        if (!orderDO.getStatus().equals(OrderStatusEnum.WAITING_PAYMENT.getValue())) {
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_STATUS_NOT_CANCEL.getCode());
        }

        OrderCancelDO orderCancelDO
                = (OrderCancelDO) new OrderCancelDO()
                .setOrderId(orderDO.getId())
                .setOrderNo(orderDO.getOrderNo())
                .setReason(reason)
                .setOtherReason(otherReason)
                .setCreateTime(new Date())
                .setUpdateTime(null);

        // 关闭订单，修改状态 item
        // TODO FROM 芋艿 TO 小范，更新的时候，where 里面带下 status 避免并发的问题
        orderItemMapper.updateByOrderId(
                orderId,
                new OrderItemDO().setStatus(OrderStatusEnum.CLOSED.getValue())
        );

        // 关闭订单，修改状态 order
        orderMapper.updateById(new OrderDO().setId(orderId).setStatus(OrderStatusEnum.CLOSED.getValue()));
        // 保存取消订单原因
        orderCancelMapper.insert(orderCancelDO);
        return CommonResult.success(null);
    }

    @Override
    @Transactional // TODO FROM 芋艿 TO 小范：泛型，一定要明确哈。
    public CommonResult orderDelivery(OrderDeliveryDTO orderDelivery) {
        List<Integer> orderItemIds = orderDelivery.getOrderItemIds();

        // 获取所有订单 items // TODO FROM 芋艿 TO 小范，deleted 是默认条件，所以 by 里面可以不带哈
        List<OrderItemDO> allOrderItems = orderItemMapper.selectByDeletedAndOrderId(DeletedStatusEnum.DELETED_NO.getValue(), orderDelivery.getOrderId());

        // 当前需要发货订单，检查 id 和 status
        List<OrderItemDO> needDeliveryOrderItems = allOrderItems.stream()
                .filter(orderItemDO -> orderItemIds.contains(orderItemDO.getId())
                        && OrderStatusEnum.WAIT_SHIPMENT.getValue() == orderItemDO.getStatus())
                .collect(Collectors.toList()); // TODO 芋艿，如果这里只是比对数字，可以用 Lambda 求和，不需要弄成一个集合的
        // 发货订单，检查
        if (needDeliveryOrderItems.size() != orderItemIds.size()) {
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_DELIVERY_INCORRECT_DATA.getCode());
        }

        OrderRecipientDO orderRecipientDO = orderRecipientMapper.selectByOrderId(orderDelivery.getOrderId());
        OrderLogisticsDO orderLogisticsDO = OrderLogisticsConvert.INSTANCE.convert(orderRecipientDO);
        // 保存物流信息
        orderLogisticsDO
                .setLogisticsNo(orderDelivery.getLogisticsNo())
                .setLogistics(orderDelivery.getLogistics())
                .setCreateTime(new Date())
                .setUpdateTime(null);
        orderLogisticsMapper.insert(orderLogisticsDO);

        // 关联订单item 和 物流信息
        // TODO FROM 芋艿 TO 小范，更新的时候，where 里面带下 status 避免并发的问题，然后判断下更新数量，不对，就抛出异常。
        orderItemMapper.updateByIds(
                orderItemIds,
                new OrderItemDO()
                        .setOrderLogisticsId(orderLogisticsDO.getId())
                        .setStatus(OrderStatusEnum.ALREADY_SHIPMENT.getValue())
        );

        // 子订单是否全部发货，如果发完，就更新 order
        List<OrderItemDO> unShippedOrderItems = allOrderItems.stream()
                .filter(orderItemDO -> OrderStatusEnum.WAIT_SHIPMENT.getValue() == orderItemDO.getStatus()
                        && !orderItemIds.contains(orderItemDO.getId()))
                .collect(Collectors.toList());
        if (unShippedOrderItems.size() <= 0) {
            // TODO FROM 芋艿 TO 小范，更新的时候，where 里面带下 status 避免并发的问题
            orderMapper.updateById(
                    new OrderDO()
                            .setId(orderDelivery.getOrderId())
                            .setStatus(OrderStatusEnum.ALREADY_SHIPMENT.getValue())
            );
        }
        // 返回成功
        return CommonResult.success(null);
    }

    @Override
    public CommonResult updateOrderRemake(Long orderId, String remake) {
        // 此处不做订单校验，直接设置备注即可
        orderMapper.updateById(new OrderDO().setId(orderId).setRemark(remake));
        return CommonResult.success(null);
    }

    @Override
    @Transactional // TODO FROM 芋艿 to 小范，先不做这个功能，电商一班不存在这个功能哈。
    public CommonResult deleteOrderItem(OrderItemDeletedDTO orderItemDeletedDTO) {
        Long orderId = orderItemDeletedDTO.getOrderId();
        List<Integer> orderItemIds = orderItemDeletedDTO.getOrderItemIds();

        // 获取当前有效的订单 item
        List<OrderItemDO> orderItemDOList = orderItemMapper
                .selectByDeletedAndOrderId(DeletedStatusEnum.DELETED_NO.getValue(), orderId);

        List<OrderItemDO> effectiveOrderItems = orderItemDOList.stream()
                .filter(orderItemDO -> !orderItemIds.contains(orderItemDO.getId()))
                .collect(Collectors.toList());

        // 检查订单 item，必须要有一个 item
        if (CollectionUtils.isEmpty(effectiveOrderItems)) {
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_ITEM_ONLY_ONE.getCode());
        }

        // 更新订单 item
        orderItemMapper.updateByIds(
                orderItemIds,
                (OrderItemDO) new OrderItemDO()
                        .setDeleted(DeletedStatusEnum.DELETED_YES.getValue())
        );

        // 更新订单 amount
//        Integer totalAmount = orderCommon.calculatedAmount(effectiveOrderItems);
        Integer totalAmount = -1; // TODO 芋艿，需要修改下，价格相关
        orderMapper.updateById(
                new OrderDO()
                        .setId(orderId)
                        .setPayAmount(totalAmount)
        );
        return CommonResult.success(null);
    }


    @Override
    @GlobalTransactional
    public  CommonResult closeExpireOrder(Long orderId){
        OrderDO orderDO=orderMapper.selectById(orderId);
        if (orderDO!=null&& OrderStatusEnum.WAITING_PAYMENT.getValue()==orderDO.getStatus()){
            orderMapper.updateOrderStatus(orderId,OrderStatusEnum.CLOSED.getValue());
            List<OrderItemDO> orderItemDOs=orderItemMapper.selectByDeletedAndOrderId(0,orderId);
            productSpuService.recoveryProductSkuQuantity(orderItemDOs.stream().map(orderItemDO -> {return new ProductSkuDecreaseNumDTO(orderItemDO.getSkuId(),orderItemDO.getQuantity());}).collect(Collectors.toList()));
            return CommonResult.ok();
        }
        return CommonResult.ok();
    }

    @Override
    public CommonResult confirmReceiving(String userId, Long orderId) {
        OrderDO orderDO = orderMapper.selectById(orderId);

        // 是否该用户的订单
        if (!userId.equals(orderDO.getUserId())) {
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_NOT_USER_ORDER.getCode());
        }

        if (OrderStatusEnum.ALREADY_SHIPMENT.getValue() != orderDO.getStatus()) {
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_UNABLE_CONFIRM_ORDER.getCode());
        }

        // TODO FROM 芋艿 TO 小范，更新的时候，where 里面带下 status 避免并发的问题
        orderMapper.updateById(
                new OrderDO()
                        .setId(orderId)
                        .setReceiverTime(new Date())
                        .setStatus(OrderStatusEnum.COMPLETED.getValue())

        );

        orderItemMapper.updateByOrderId(
                orderId,
                new OrderItemDO()
                        .setStatus(OrderStatusEnum.COMPLETED.getValue())
                        .setReceiverTime(new Date())
        );
        return CommonResult.success(null);
    }

    @Override
    public CommonResult updateLogistics(OrderLogisticsUpdateDTO orderLogisticsDTO) {
        OrderLogisticsDO orderLogisticsDO = OrderLogisticsConvert.INSTANCE.convert(orderLogisticsDTO);
        orderLogisticsMapper.updateById(orderLogisticsDO);
        return CommonResult.success(null);
    }

    @Override
    public CommonResult deleteOrder(Long id) {
        // 删除订单操作，一般用于 用户端删除，是否存在检查可以过掉
        orderMapper.updateById((OrderDO) new OrderDO()
                .setId(id)
                .setDeleted(DeletedStatusEnum.DELETED_YES.getValue())
        );
        return CommonResult.success(null);
    }

    @Override
    @GlobalTransactional
    public String updatePaySuccess(Long orderId, Integer payAmount) {
        OrderDO order = orderMapper.selectById(orderId);
        log.info("updatePaySuccess");
        if (order == null) { // 订单不存在
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_NOT_EXISTENT.getCode()).getMessage();
        }
        if (!order.getStatus().equals(OrderStatusEnum.WAITING_PAYMENT.getValue())) { // 状态不处于等待支付
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_STATUS_NOT_WAITING_PAYMENT.getCode()).getMessage();
        }
        if (!order.getPresentPrice().equals(payAmount)) { // 支付金额不正确
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_PAY_AMOUNT_ERROR.getCode()).getMessage();
        }
        // 更新 OrderDO 状态为已支付，等待发货
        OrderDO updateOrderObj = new OrderDO()
                .setStatus(OrderStatusEnum.WAIT_SHIPMENT.getValue())
                .setPayAmount(payAmount)
                .setPaymentTime(new Date());
        int updateCount = orderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), updateOrderObj);
        if (updateCount <= 0) {
            return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_STATUS_NOT_WAITING_PAYMENT.getCode()).getMessage();
        }
        generatorOrderCredential(new OrderCredentialDTO().setOrderId(orderId).setPayTime(new java.sql.Date(System.currentTimeMillis())));
        OrderItemDO orderItemDO = new OrderItemDO();
        orderItemDO.setPaymentTime(new Date()).setStatus(OrderStatusEnum.WAIT_SHIPMENT.getValue());

        orderItemMapper.updateByOrderId(orderId, orderItemDO);
        log.info(String.valueOf(updateCount));
        // TODO FROM 芋艿 to 小范，把更新 OrderItem 给补全。
        return "success";
    }

    @Override
    public CommonResult listenerConfirmGoods() {
        return null;
    }

    @Override
    public CommonResult listenerExchangeGoods() {
        return null;
    }

    @Override
    public CommonResult generatorOrderCredential(OrderCredentialDTO orderCredentialDTO) {

        if (ObjectUtils.isNull(orderCredentialDTO.getOrderId(), orderCredentialDTO.getPayTime())) {
            return CommonResult.error("参数不足");
        }
        OrderDO orderDO = orderMapper.selectById(orderCredentialDTO.getOrderId());
        if (!orderMapper.updateOrderStatus(orderDO.getId(), OrderStatusEnum.ALREADY_SHIPMENT.getValue())) {
            throw ServiceExceptionUtil.exception(100000, "更新状态失败");
        }
        OrderCredential orderCredential = new OrderCredential();
        orderCredential.setOrderId(orderCredentialDTO.getOrderId());
        orderCredential.setOrderNo(orderDO.getOrderNo());
        orderCredential.setId(generatorSnowFlakeIDUtils.nextId());
        try {
            orderCredential.setSecretText(AesEncryptUtil.encrypt(orderDO.getOrderNo(), EncryptedString.key, EncryptedString.iv));
        } catch (Exception e) {
            return CommonResult.error(e.getMessage());
        }

        orderCredential.setIsConsume(false);
        orderCredential.setIsDelete(false);
        orderCredential.setUpdateTime(new DateTime());
        if (orderCredentialMapper.insert(orderCredential) <= 0) {
            throw ServiceExceptionUtil.exception(10000, "更新状态失败");
        }
        return CommonResult.ok();
    }


    @Override
    public CommonResult writeOffOrderCredential(WriteOffOrderCredentialDTO dto) {

        OrderCredential credential = orderCredentialMapper.getOneByOrderId(dto.getOrderId());

        Long orderId = dto.getOrderId();
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (orderDO==null){
            return CommonResult.error("订单不存在");
        }
        if (OrderStatusEnum.ALREADY_SHIPMENT.getValue()!=orderDO.getStatus()) {
            return CommonResult.error("订单已关闭");
        }
        if (!relationShipService.sellerIsInShop(dto.getSellerId(), orderDO.getShopId()).isSuccess()) {
            return CommonResult.error("该用户物权限处理该订单");
        }

        Long time = cn.hutool.core.date.DateUtil.between(credential.getUpdateTime(), new DateTime(System.currentTimeMillis()), DateUnit.MINUTE);
        if (time > CommonConstant.ORDER_SECRET_UPDATE_TIME) {

            return CommonResult.error("密钥已过期，请刷新");
        }
        if (credential.getSecretText() != null && credential.getSecretText().equals(dto.getSecretText())) {
            saveWriteOrderInfo(dto, credential, orderId);
        } else {
            return CommonResult.error("密钥不正确");
        }


        return CommonResult.ok();
    }
    @GlobalTransactional(rollbackFor = Exception.class)
    private void saveWriteOrderInfo(WriteOffOrderCredentialDTO dto, OrderCredential credential, Long orderId) {
        credential.setSellerId(dto.getSellerId());
        credential.setConsumeIp(dto.getIp());
        credential.setConsumeMac(dto.getMac());
        credential.setConsumeTime(dto.getConsumeTime());
        credential.setIsConsume(true);
        credential.setUpdateTime(new DateTime());
        orderCredentialMapper.updateById(credential);
        OrderDO orderDb = new OrderDO();
        orderDb.setId(orderId);
        orderDb.setStatus(OrderStatusEnum.COMPLETED.getValue());
        orderDb.setUpdateTime(new Date());
        orderDb.setClosingTime(new Date());
        orderMapper.updateById(orderDb);
        shopService.addShopIncome(orderDb.getShopId(),orderDb.getPresentPrice());
    }

    @Override
    public CommonResult<OrderCredentialBO> getPersonalOrderCredential(CredentialVerifyDTO dto) {

        OrderDO orderDO = orderMapper.selectById(dto.getOrderId());
        if (orderDO == null || !orderDO.getStatus().equals(OrderStatusEnum.ALREADY_SHIPMENT.getValue()) || !orderDO.getUserId().equals(dto.getUserId())) {
            return CommonResult.error("");
        }
        //TODO 常用设备校验

        OrderCredential credential = orderCredentialMapper.getOneByOrderId(dto.getOrderId());
        if (credential == null) {
            return CommonResult.error("");
        }
        Long time = cn.hutool.core.date.DateUtil.between(credential.getUpdateTime(), new DateTime(System.currentTimeMillis()), DateUnit.MINUTE);
        OrderCredential updateDb = new OrderCredential();
        if (time > CommonConstant.ORDER_SECRET_UPDATE_TIME) {
            try {
                updateDb.setId(credential.getId()).setUpdateTime(new DateTime()).setSecretText
                        (AesEncryptUtil.encrypt(orderDO.getOrderNo(), EncryptedString.key, EncryptedString.iv));
                orderCredentialMapper.updateById(updateDb);
                credential.setSecretText(updateDb.getSecretText()).setUpdateTime(updateDb.getUpdateTime());

            } catch (Exception e) {
                return CommonResult.error("更新密钥失败，请重新获取二维码");
            }
        }else {
            credential.setSecretText(credential.getSecretText()).setUpdateTime(credential.getUpdateTime());
        }

        return CommonResult.success(ObjectUtils.copyObject(credential, OrderCredentialBO.class));

    }


    @Override
    public String testDubbo(String s) {
        System.out.println(s);
        return s;
    }

    /**
     * 根据ID查询订单详情
     *
     * @param orderQueryDTO
     * @return
     */
    @Override
    public CommonResult<OrderPageBO> getOrders(OrderQueryDTO orderQueryDTO) {
        int totalCount = orderMapper.selectPageCount(orderQueryDTO);
        if (totalCount == 0) {
            return CommonResult.success(new OrderPageBO().setOrders(Collections.emptyList()).setTotal(0));
        }

        // 获取订单数据
        List<OrderDO> orderDOList = orderMapper.getOrders(orderQueryDTO);

        if (CollectionUtils.isEmpty(orderDOList)) {
            return CommonResult.success(new OrderPageBO().setOrders(Collections.emptyList()).setTotal(totalCount));
        }

        // 获取订单 id
        Set<Long> orderIds = orderDOList.stream()
                .map(orderDO -> orderDO.getId())
                .collect(Collectors.toSet());

        // 获取配送信息
        List<OrderRecipientDO> orderRecipientDOList = orderRecipientMapper.selectByOrderIds(orderIds);
        List<OrderRecipientBO> orderRecipientBOList = OrderRecipientConvert.INSTANCE.convert(orderRecipientDOList);
        Map<Long, OrderRecipientBO> orderRecipientBOMap
                = orderRecipientBOList.stream().collect(Collectors.toMap(OrderRecipientBO::getOrderId, obj -> obj));

        // 获取 订单的 items
        List<OrderItemDO> orderItemDOList = orderItemMapper
                .selectByDeletedAndOrderIds(orderIds, DeletedStatusEnum.DELETED_NO.getValue());
        List<OrderItemBO> orderItemBOList = OrderItemConvert.INSTANCE.convertOrderItemDO(orderItemDOList);

        Map<Long, List<OrderItemBO>> orderItemBOMultimap = orderItemBOList.stream().collect(
                Collectors.toMap(
                        OrderItemBO::getOrderId,
                        item -> Lists.newArrayList(item),
                        (oldVal, newVal) -> {
                            oldVal.addAll(newVal);
                            return oldVal;
                        }
                )
        );

        // 转换 orderDO 为 OrderBO，并设置 item
        List<OrderBO> orderPageBOList = OrderConvert.INSTANCE.convertPageBO(orderDOList);
        List<OrderBO> result = orderPageBOList.stream().map(orderBO -> {
            if (orderItemBOMultimap.containsKey(orderBO.getId())) {
                orderBO.setOrderItems(orderItemBOMultimap.get(orderBO.getId()));
            }
            if (orderRecipientBOMap.containsKey(orderBO.getId())) {
                orderBO.setOrderRecipient(orderRecipientBOMap.get(orderBO.getId()));
            }
            return orderBO;
        }).collect(Collectors.toList());
        return CommonResult.success(
                new OrderPageBO()
                        .setTotal(totalCount)
                        .setOrders(result)
        );
    }

    @Override
    public OrderBO getOrderById(Long orderId) {
        OrderDO order = orderMapper.selectById(orderId);
        return ObjectUtils.copyObject(order, OrderBO.class);
    }

    @Override
    public CommonResult<OrderPageBO> getOrderPageByClerkId(String clerkId, Integer pageNo, Integer pageSize) {

        int totalCount = orderMapper.selectPageCountByClerkId(clerkId);
        if (totalCount == 0) { // TODO FROM 芋艿 TO 小范 Collections.EMPTY_LIST 改成 Collections.emptyList()
            return CommonResult.success(new OrderPageBO().setOrders(Collections.emptyList()).setTotal(0));
        }
        // 获取订单数据
        List<OrderDO> orderDOList = orderMapper.selectPageByClerkId(clerkId, pageNo, pageSize);

        if (CollectionUtils.isEmpty(orderDOList)) {
            return CommonResult.success(new OrderPageBO().setOrders(Collections.emptyList()).setTotal(totalCount));
        }
        return CommonResult.success(
                new OrderPageBO()
                        .setTotal(totalCount)
                        .setOrders(ObjectUtils.copyList(orderDOList, OrderBO.class))
        );
    }

    @Override
    public CommonResult<List<OrderPayAllChartBO>> getpayAllChart(OrdersVO ordersVO) {
        List<String> shopIds = ordersVO.getShopIds();
        Integer type=ordersVO.getType();
        List<OrderDO> list;
        switch(type){
            case 1:
                Long dailyStartTime = TimeUtils.getDailyStartTime(System.currentTimeMillis(), "GMT+8:00");
                String s = TimeUtils.timestampToStr(dailyStartTime);
                Long dailyEndTime = TimeUtils.getDailyEndTime(System.currentTimeMillis(), "GMT+8:00");
                String e = TimeUtils.timestampToStr(dailyEndTime);
                ordersVO.setStartCreateTime(s);
                ordersVO.setEndCreateTime(e);
                log.info(JacksonUtils.toJSONString(ordersVO));
                list= orderMapper.countDay(shopIds,ordersVO);
                break;
            case 3:
                Long monthStartTime = TimeUtils.getMonthStartTime(System.currentTimeMillis(), "GMT+8:00");
                String s1 = TimeUtils.timestampToStr(monthStartTime);
                Long monthEndTime = TimeUtils.getMonthEndTime(System.currentTimeMillis(), "GMT+8:00");
                String s2 = TimeUtils.timestampToStr(monthEndTime);
                ordersVO.setStartCreateTime(s1);
                ordersVO.setEndCreateTime(s2);
                list= orderMapper.countDay(shopIds,ordersVO);
                break;
            default:
                list=  orderMapper.countYear(shopIds);
                break;
        }
        // 转换 orderDO 为 OrderPayAllChartBO
        List<OrderPayAllChartBO> orderPayAllChartBOS = OrderPayConvert.INSTANCE.converPayBO(list);
        return CommonResult.success(orderPayAllChartBOS);
    }

    @Override
    public CommonResult<List<OrderPayAllChartBO>> getpayMonth(OrdersVO ordersVO) {
        Integer type=ordersVO.getType();
        List<OrderDO> list;
        switch(type){
            case 3:
                Long monthStartTime = TimeUtils.getMonthStartTime(System.currentTimeMillis(), "GMT+8:00");
                String s1 = TimeUtils.timestampToStr(monthStartTime);
                Long monthEndTime = TimeUtils.getMonthEndTime(System.currentTimeMillis(), "GMT+8:00");
                String s2 = TimeUtils.timestampToStr(monthEndTime);
                ordersVO.setStartCreateTime(s1);
                ordersVO.setEndCreateTime(s2);
                list = orderMapper.countMonth(ordersVO.getShopIds(), ordersVO);
                break;
            default:
                list = orderMapper.countMonth(ordersVO.getShopIds(), ordersVO);
                break;
        }
        List<OrderPayAllChartBO> bo=ObjectUtils.copyList(list,OrderPayAllChartBO.class);
        List<OrderPayAllChartBO> orderPayAllChartBOS = OrderPayConvert.INSTANCE.converPayBO(list);
        System.out.println(orderPayAllChartBOS);
        return CommonResult.success(bo);
    }

    @Override
    public Map<String, Integer> getpayMonthofYear(OrdersVO ordersVO) {
        List<String> shopIds = ordersVO.getShopIds();
        Integer type = ordersVO.getType();
        List<OrderDO> list;
        Map<String, Integer> resultYearofMonth = null;
        switch (type) {
            case 2:
                Date beginDayOfWeek = TimeUtils.getBeginDayOfWeek();
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date endDayOfWeek = TimeUtils.getEndDayOfWeek();
                ordersVO.setStartCreateTime(simpleDateFormat.format(beginDayOfWeek));
                ordersVO.setEndCreateTime(simpleDateFormat.format(endDayOfWeek));
                list=orderMapper.countWeek(shopIds,ordersVO);
                resultYearofMonth = new HashMap<>();
                SimpleDateFormat week=new SimpleDateFormat("dd");
                for (OrderDO iweek : list){
                    if(resultYearofMonth.containsKey(week.format(iweek.getClosingTime()))){
                        Integer integers=resultYearofMonth.get(week.format(iweek.getClosingTime()))+iweek.getPresentPrice();
                        resultYearofMonth.put(week.format(iweek.getClosingTime()),integers);
                    }else {
                        resultYearofMonth.put(week.format(iweek.getClosingTime()),iweek.getPresentPrice());
                    }
                }
                break;
            case 3:
                Long monthStartTime = TimeUtils.getMonthStartTime(System.currentTimeMillis(), "GMT+8:00");
                String s1 = TimeUtils.timestampToStr(monthStartTime);
                Long monthEndTime = TimeUtils.getMonthEndTime(System.currentTimeMillis(), "GMT+8:00");
                String s2 = TimeUtils.timestampToStr(monthEndTime);
                ordersVO.setStartCreateTime(s1);
                ordersVO.setEndCreateTime(s2);
                list = orderMapper.countWeek(shopIds, ordersVO);
                resultYearofMonth = new HashMap<>();
                SimpleDateFormat sdf = new SimpleDateFormat("dd");
                for (OrderDO item : list) {
                    if (resultYearofMonth.containsKey(sdf.format(item.getClosingTime())+"号")) {
                        Integer integers = resultYearofMonth.get(sdf.format(item.getClosingTime())+"号") + item.getPresentPrice();
                        resultYearofMonth.put(sdf.format(item.getClosingTime())+"号", integers);
                    } else {
                        resultYearofMonth.put( sdf.format(item.getClosingTime())+"号", item.getPresentPrice());
                    }

                }
                break;
            case 4:
                Long yearStartTime = TimeUtils.getYearStartTime(System.currentTimeMillis(), "GMT+8:00");
                String s3 = TimeUtils.timestampToStr(yearStartTime);
                Long yearEndTime = TimeUtils.getYearEndTime(System.currentTimeMillis(), "GMT+8:00");
                String s4 = TimeUtils.timestampToStr(yearEndTime);
                ordersVO.setStartCreateTime(s3);
                ordersVO.setEndCreateTime(s4);
                list = orderMapper.countWeek(shopIds, ordersVO);
                resultYearofMonth = new HashMap<>();
                SimpleDateFormat year = new SimpleDateFormat("MM");
                for (OrderDO month : list) {
                    if (resultYearofMonth.containsKey(year.format(month.getClosingTime())+"月")) {
                        Integer monthPrices = resultYearofMonth.get(year.format(month.getClosingTime())+"月") + month.getPresentPrice();
                        resultYearofMonth.put(year.format(month.getClosingTime())+"月", monthPrices);
                    } else {
                        resultYearofMonth.put(year.format(month.getClosingTime())+"月", month.getPresentPrice());
                    }
                }
                break;
            default:
        }
        return resultYearofMonth;
    }

    /**
     * 查询订单（图表用）
     * @param shopIds
     * @param startTime
     * @param endTime
     */
    @Override
    public CommonResult<List<OrderBO>> getOrdersForChart(List<String> shopIds, String startTime, String endTime) {
        if(shopIds == null || shopIds.size() == 0){
            return CommonResult.error("");
        }
        return CommonResult.success(OrderConvert.INSTANCE.convertPageBO(orderMapper.getOrdersForChart(shopIds,startTime,endTime)));
    }

    @Override
    public CommonResult<OrderPageBO> getOrderPageByShopIds(OrderQueryDTO orderQueryDTO) {

        int totalCount = orderMapper.selectPageCountByShopIds(orderQueryDTO);
        if (totalCount == 0) { // TODO FROM 芋艿 TO 小范 Collections.EMPTY_LIST 改成 Collections.emptyList()
            return CommonResult.success(new OrderPageBO().setOrders(Collections.emptyList()).setTotal(0));
        }

        // 获取订单数据
        List<OrderDO> orderDOList = orderMapper.selectPageByShopIds(orderQueryDTO);

        if (CollectionUtils.isEmpty(orderDOList)) {
            return CommonResult.success(new OrderPageBO().setOrders(Collections.emptyList()).setTotal(totalCount));
        }

        // 获取订单 id
        Set<Long> orderIds = orderDOList.stream()
                .map(orderDO -> orderDO.getId())
                .collect(Collectors.toSet());


        // 获取 订单的 items
        List<OrderItemDO> orderItemDOList = orderItemMapper
                .selectByDeletedAndOrderIds(orderIds, DeletedStatusEnum.DELETED_NO.getValue());
        List<OrderItemBO> orderItemBOList = OrderItemConvert.INSTANCE.convertOrderItemDO(orderItemDOList);

        Map<Long, List<OrderItemBO>> orderItemBOMultimap = orderItemBOList.stream().collect(
                Collectors.toMap(
                        OrderItemBO::getOrderId,
                        item -> Lists.newArrayList(item),
                        (oldVal, newVal) -> {
                            oldVal.addAll(newVal);
                            return oldVal;
                        }
                )
        );

        // 转换 orderDO 为 OrderBO，并设置 item
        List<OrderBO> orderPageBOList = OrderConvert.INSTANCE.convertPageBO(orderDOList);
        List<OrderBO> result = orderPageBOList.stream().map(orderBO -> {
            if (orderItemBOMultimap.containsKey(orderBO.getId())) {
                orderBO.setOrderItems(orderItemBOMultimap.get(orderBO.getId()));
            }
            return orderBO;
        }).collect(Collectors.toList());
        return CommonResult.success(
                new OrderPageBO()
                        .setTotal(totalCount)
                        .setOrders(result)
        );    }

    @Override
    public CommonResult<Map<Object,Object>> getOrderConversionRate(List<String> shopIds, OrdersVO ordersVO) {
        Map map = new HashMap();
        if(shopIds == null || shopIds.size() == 0){
            return CommonResult.error("");
        }
        double totalOrders = orderMapper.getTotalOrders(shopIds,ordersVO);

        double completedOrders = orderMapper.getCompletedOrders(shopIds,ordersVO);

        ordersVO.setTotalOrders(totalOrders);
        ordersVO.setCompletedOrders(completedOrders);

        List<OrderDO> orderDOS = orderMapper.OrdersCountOfWeek(shopIds, ordersVO);
        List<OrderBO> orderBOList = OrderConvert.INSTANCE.convertPageBO(orderDOS);
        map.put("ordersVO",ordersVO);
        map.put("orderBOList",orderBOList);
        return CommonResult.success(map);
    }

    /**
     * 根据店员ID获取核销笔数
     * @param clerkIds
     * @param startTime
     * @param endTime
     */
    @Override
    public CommonResult<Integer> getOrderCancellationData(List<String> clerkIds, String startTime, String endTime) {
        return CommonResult.success(orderMapper.getOrderCancellationData(clerkIds, startTime, endTime));
    }

    @Override
    public CommonResult<List<OrderBO>> getOrderListByShopIds(List<String> shopIds) {
        if (shopIds.isEmpty()){
            return CommonResult.error("");
        }
        List<OrderDO> orderDOList= orderMapper.getOrdersForChart(shopIds, DateUtils.formatTime(new Date()),DateUtils.formatTime(new Date()));
        List<OrderBO> orderBOList = OrderConvert.INSTANCE.convertPageBO(orderDOList);

        return CommonResult.success(orderBOList);
    }

    /**
     * 获取商户 各个店铺一个月的销售额
     * @param ordersVO
     * @return
     */
    @Override
    public CommonResult<List<OrderBO>> getpayMonthForSalesVolume(OrdersVO ordersVO) {
        if(ordersVO == null){
            return CommonResult.error("参数错误");
        }
        List<OrderDO> orderDOS = orderMapper.countWeek(ordersVO.getShopIds(), ordersVO);
        orderDOS.stream().collect(Collectors.groupingBy(OrderDO::getShopId));
        return CommonResult.success(OrderConvert.INSTANCE.convertPageBO(orderDOS));
    }

    @Override
    public CommonResult<List<OrderBO>> getOrderBOListByWhereCondition(OrderQueryDTO queryDTO) {
        List<OrderDO> orderDOS=orderMapper.getOrdersByWhereCondition(queryDTO);
        JacksonUtils.toJSONString(orderDOS);
        return CommonResult.success(OrderConvert.INSTANCE.convertPageBO(orderDOS));
    }

    @Override
    public OrdersPageBO getSellerPage(OrdersPageDTO ordersPageDTO) {
        OrdersPageBO ordersPageBO = new OrdersPageBO();
        //查询商店订单数据
        int offers=(ordersPageDTO.getPageNo() - 1) * ordersPageDTO.getPageSize();
        ordersPageBO.setList(OrderCommentConvert.INSTANCE.converTB(orderMapper.selectSellerList(
                ordersPageDTO.getOrderNo(),ordersPageDTO.getStatus(),ordersPageDTO.getShopIds()
                ,offers,ordersPageDTO.getPageSize()
        )));
        //查询商店订单数量
        ordersPageBO.setTotal(orderMapper.selectSellerPageCount(
                ordersPageDTO.getOrderNo(),ordersPageDTO.getStatus(),
                ordersPageDTO.getShopIds()
        ));

        return ordersPageBO;
    }
}